package com.lvtulife.common.service.impl;

import com.baomidou.mybatisplus.mapper.AutoMapper;
import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.plugins.Page;
import com.baomidou.mybatisplus.toolkit.CollectionUtil;
import com.lvtulife.common.component.constants.ConstantUtil;
import com.lvtulife.common.component.exception.ErrMsg;
import com.lvtulife.common.entity.BaseEntity;
import com.lvtulife.common.service.BaseServiceI;
import com.lvtulife.util.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert;

import java.io.Serializable;
import java.util.List;
import java.util.Map;

/**
 * 基础业务逻辑
 * 注意: 此层不建议加入切面日志，如需要加入切面日志建议在业务层加入
 * 主键 Long 类型 IService 实现类（ 泛型：M 是 mapper 对象， T 是实体 ）
 *
 * @param <T>
 * @author valuegroup
 */
public class BaseServiceImpl<M extends AutoMapper<T>, T extends BaseEntity> implements BaseServiceI<T> {
    /**
     * 子类不用再定义logger对象
     */
    protected Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    protected M baseMapper;

    /**
     * 判断数据库操作是否成功
     *
     * @param result 数据库操作返回影响条数
     * @return boolean
     */
    protected boolean retBool(int result) {
        return result >= 1;
    }

    /**
     * 判断是否操作成功,不成功抛出异常
     *
     * @param result
     */
    protected void checkOperation(int result) {
        checkOperation(retBool(result));
    }

    /**
     * 验证常量值是否在有效范围内
     *
     * @param key
     * @param status
     */
    protected void verifyConstant(String key, Integer status) {
        if (!ConstantUtil.getInstance().verifyConstant(key, status)) {
            throw new RuntimeException(ErrMsg.INVALID_CONTENT.getMsg());
        }
    }

    /**
     * 判断是否操作成功,不成功抛出异常
     *
     * @param result
     */
    protected void checkOperation(boolean result) {
        if (!result) {
            throw new RuntimeException(ErrMsg.OPERATION_FAILURE.getMsg());
        }
    }

    /**
     * 验证参数非空
     *
     * @param objs
     */
    protected void verifyParams(Object... objs) {
        for (Object obj : objs) {
            Assert.notNull(obj, ErrMsg.NO_CONTENT.getMsg());

            /* 字符类型 */
            if (obj instanceof String) {
                if (StringUtils.isBlank((String) obj)) {
                    throw new IllegalArgumentException(ErrMsg.NO_CONTENT.getMsg());
                }
            }
        }
    }

    public T verifyEntity(T t) {
        verifyParams(t.getId());

        int size = selectCount(t);
        if (size == 0)
            throw new IllegalArgumentException(formatNO_OBJECT(t, t.getId()));

        return t;
    }

    public T getEntity(Serializable id) {
        verifyParams(id);

        T entity = selectById(id);
        Assert.notNull(entity, formatNO_OBJECT(entity, id));
        return entity;
    }


    /**
     * <p>
     * TableId 注解存在更新记录，否插入一条记录
     * </p>
     *
     * @param entity      实体对象
     * @param isSelective true 选择字段 false 不选择字段
     * @return boolean
     */
    @Transactional(rollbackFor = Exception.class)
    public boolean insertOrUpdate(T entity, boolean isSelective) {
        if (null != entity) {
            if (null != entity.getId()) {
                return isSelective ? insertSelective(entity) : insert(entity);
            } else {
                return isSelective ? updateSelectiveById(entity) : updateById(entity);
            }
        }
        return false;
    }

    public boolean insertOrUpdate(T entity) {
        return insertOrUpdate(entity, false);
    }

    public boolean insertOrUpdateSelective(T entity) {
        return insertOrUpdate(entity, true);
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean insert(T entity) {
        return retBool(baseMapper.insert(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean insertSelective(T entity) {
        return retBool(baseMapper.insertSelective(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean insertBatch(List<T> entityList) {
        return retBool(baseMapper.insertBatch(entityList));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean deleteById(Serializable id) {
        return retBool(baseMapper.deleteById(id));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean deleteByMap(Map<String, Object> columnMap) {
        return retBool(baseMapper.deleteByMap(columnMap));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean deleteSelective(T entity) {
        return retBool(baseMapper.deleteSelective(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatchIds(List<? extends Serializable> idList) {
        return retBool(baseMapper.deleteBatchIds(idList));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateById(T entity) {
        return retBool(baseMapper.updateById(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateSelectiveById(T entity) {
        return retBool(baseMapper.updateSelectiveById(entity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean update(T entity, T whereEntity) {
        return retBool(baseMapper.update(entity, whereEntity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateSelective(T entity, T whereEntity) {
        return retBool(baseMapper.updateSelective(entity, whereEntity));
    }

    @Transactional(rollbackFor = Exception.class)
    public boolean updateBatchById(List<T> entityList) {
        return retBool(baseMapper.updateBatchById(entityList));
    }

    public T selectById(Serializable id) {
        return baseMapper.selectById(id);
    }

    public List<T> selectBatchIds(List<? extends Serializable> idList) {
        return baseMapper.selectBatchIds(idList);
    }

    public List<T> selectByMap(Map<String, Object> columnMap) {
        return baseMapper.selectByMap(columnMap);
    }

    public T selectOne(T entity) {
        return baseMapper.selectOne(entity);
    }

    public T selectOne(EntityWrapper<T> entityWrapper) {
        List<T> list = baseMapper.selectList(entityWrapper);
        if (CollectionUtil.isNotEmpty(list)) {
            int size = list.size();
            if (size > 1) {
                logger.warn("Warn: selectOne Method There are " + size + " results.");
            }
            return list.get(0);
        }
        return null;
    }

    public int selectCount(T entity) {
        return baseMapper.selectCount(entity);
    }

    public int selectCount(EntityWrapper<T> entityWrapper) {
        return baseMapper.selectCountByEw(entityWrapper);
    }

    public List<T> selectList(EntityWrapper<T> entityWrapper) {
        return baseMapper.selectList(entityWrapper);
    }

    public Page<T> selectPage(Page<T> page, EntityWrapper<T> entityWrapper) {
        if (null != entityWrapper) {
            entityWrapper.orderBy(page.getOrderByField(), page.isAsc());
        }
        page.setRecords(baseMapper.selectPage(page, entityWrapper));
        return page;
    }

    private String formatNO_OBJECT(T t, Serializable id) {
        StringBuffer msg = new StringBuffer(ErrMsg.NO_OBJECT.getMsg());
        msg.append("\tEntity:").append(t.getClass().getSimpleName()).append("[").append(id).append("]");
        return msg.toString();
    }
}
